package
{
 // bulkloader
 import br.com.stimuli.loading.BulkLoader;
 
 // papervision
 import org.papervision3d.materials.utils.MaterialsList;
 import org.papervision3d.objects.primitives.Cube;
 import org.papervision3d.lights.PointLight3D;
 import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
 import org.papervision3d.render.LazyRenderEngine;
 import org.papervision3d.scenes.Scene3D;
 import org.papervision3d.view.Viewport3D;
 
 // flash
 import flash.display.PixelSnapping;
 import flash.display.Bitmap;
 import flash.net.URLRequest;
 import flash.events.Event;
 import flash.net.URLLoaderDataFormat;
 import flash.net.URLLoader;
 import flash.display.BitmapData;
 import flash.media.Video;
 import flash.media.Camera;
 import flash.display.Sprite;
 import org.papervision3d.objects.DisplayObject3D;
 
 // libspark
 import org.libspark.flartoolkit.core.FLARCode;
 import org.libspark.flartoolkit.core.param.FLARParam;
 import org.libspark.flartoolkit.core.raster.rgb.FLARRgbRaster_BitmapData;
 import org.libspark.flartoolkit.core.transmat.FLARTransMatResult;
 import org.libspark.flartoolkit.detector.FLARMultiMarkerDetector;
 import org.libspark.flartoolkit.support.pv3d.FLARBaseNode;
 import org.libspark.flartoolkit.support.pv3d.FLARCamera3D;
 
 public class FlarMultiMarkerDemo extends Sprite
 {
  // flar properties
  private var _camParameters:FLARParam;
  private var _raster:FLARRgbRaster_BitmapData;
  private var _detector:FLARMultiMarkerDetector;
  private var _flarCam3D:FLARCamera3D;
  private var _resultMat:FLARTransMatResult;
 
  // flash properties
  private var _cam:Camera;
  private var _vid:Video;
  private var _capture:Bitmap;
  private var _loader:URLLoader;
  private var _allMarkers:Array;
 
  // papervision3d
  private var _vp:Viewport3D;
  private var _scene:Scene3D;
  private var _renderer:LazyRenderEngine;
  private var _light:PointLight3D;
  private var _bLoader:BulkLoader;
 
  public function FlarMultiMarkerDemo()
  {
   _allMarkers = [
         {markerSource: "marker1.pat", segments: 4, size: 65},
         {markerSource: "marker2.pat", segments: 4, size: 65},
         {markerSource: "marker3.pat", segments: 4, size: 65},
        ];
 
   loadCamera();
  }
 
  private function loadCamera():void
  {
   _loader = new URLLoader();
   _loader.dataFormat = URLLoaderDataFormat.BINARY;
   _loader.addEventListener(Event.COMPLETE, onLoadCamParam);
   _loader.load(new URLRequest("camera_para_16x9.dat"));
  }
 
  // camera parameters are loaded, load the marker you want to use
  // camera parameters are loaded, load the marker you want to use
  private function onLoadCamParam(event:Event):void
  {
   _loader.removeEventListener(Event.COMPLETE, onLoadCamParam);
 
   // setup camera parameters
   _camParameters = new FLARParam();
   _camParameters.loadARParam(_loader.data);
   _camParameters.changeScreenSize(500, 500);
 
   // reset loader
   _loader = null;
 
   _bLoader = new BulkLoader("markerLoader");
   _bLoader.addEventListener(Event.COMPLETE, markersLoadedHandler);
   // now load multiple markers (for now its 3)
   for (var i:int = 0; i < _allMarkers.length; i++)
   {
    _bLoader.add(_allMarkers[i].markerSource, {id: "marker_" + i.toString() });
   }
   _bLoader.start();
  }
 
  private function markersLoadedHandler(event:Event):void
  {
   var codes:Vector.<FLARCode> = new Vector.<FLARCode>();
   var sizes:Vector.<Number> = new Vector.<Number>();
   for (var i:int = 0; i < _allMarkers.length; i++)
   {
    var code:FLARCode = new FLARCode(_allMarkers[i].segments, _allMarkers[i].segments, _allMarkers[i].size, _allMarkers[i].size);
    code.loadARPatt(_bLoader.getContent( "marker_" + i.toString()));
    codes.push(code);
    sizes.push(_allMarkers[i].size);
   }
 
   initWebcam();
 
   // create bitmap and bitmapdata where we can draw the webcam into
   var bmd:BitmapData = new BitmapData(500, 500, false, 0);
   _capture = new Bitmap(bmd, PixelSnapping.AUTO,false);
   _capture.width = 500;
   _capture.height = 500;
   addChild(_capture);
 
   _raster = new FLARRgbRaster_BitmapData(_capture.bitmapData);
   _detector = new FLARMultiMarkerDetector(_camParameters, codes, sizes, codes.length);
 
   initFlar();
   initPV3D();
   initListeners();
  }
 
  private function initWebcam():void
  {
   _cam = Camera.getCamera();
   _cam.setMode(500, 500, 60);
   _vid = new Video(500, 500);
   _vid.attachCamera(_cam);
  }
 
  private function initFlar():void
  {
   _flarCam3D = new FLARCamera3D(_camParameters);
   _resultMat = new FLARTransMatResult();
  }
 
  private function initPV3D():void
  {
   _vp = new Viewport3D(500, 500);
   addChild(_vp);
 
   _scene = new Scene3D();
 
   _light = new PointLight3D();
 
   // add a cube or whatever we want to show when pattern is recognised
   // in the basenode (FLARBaseNode, which extends from a DisplayObject3D)
   for (var i:int = 0; i < _allMarkers.length; i++)
   {
    var fmat:FlatShadeMaterial = new FlatShadeMaterial(_light, 0x7DC202 * Math.random(), 0xCCCCCC);
    var cube:Cube = new Cube(new MaterialsList({all: fmat}), 40, 40, 80);
    cube.z = 20;
    cube.name = "cube_" + i.toString();
    var baseNode:FLARBaseNode = new FLARBaseNode();
    baseNode.name = "baseNode_" + i;
    baseNode.addChild(cube);
    _scene.addChild(baseNode);
   }
 
   _renderer = new LazyRenderEngine(_scene, _flarCam3D, _vp);
  }
 
  private function initListeners():void
  {
   addEventListener(Event.ENTER_FRAME, render);
  }
 
  private function render(event:Event):void
  {
   _capture.bitmapData.draw(_vid);
 
   for (var i:int = 0; i< _allMarkers.length; i++)
   {
    if (_detector.detectMarkerLite(_raster, 65) && _detector.getConfidence(i) > 0.5)
    {
     _detector.getTransformMatrix(i, _resultMat);
     FLARBaseNode(_scene.getChildByName("baseNode_" + i)).setTransformMatrix(_resultMat);
     _scene.getChildByName("baseNode_" + i).visible = true;
    }
    else
    {
     _scene.getChildByName("baseNode_" + i).visible = false;
    }
   }
 
   _renderer.render();
  }
 }
}